package cn.ticsmyc.tools.multiThread.twoPhaseTermination;

/**
 * @author Ticsmyc
 * @date 2021-06-01 17:24
 */
public abstract class AbstractTerminatableThread extends Thread implements Terminatable {

    protected final TerminationToken terminationToken;

    public AbstractTerminatableThread() {
        this(new TerminationToken());
    }

    public AbstractTerminatableThread(TerminationToken terminationToken) {
        this.terminationToken = terminationToken;
        terminationToken.register(this);
    }


    @Override
    public void run() {
        Exception ex = null;
        try {
            for (; ; ) {
                //执行处理逻辑前 先判断线程停止标志
                if(terminationToken.toShutDown && terminationToken.reservations.get() <= 0) {
                    break;
                }
                doRun();
            }
        } catch (Exception e) {
            ex = e;
            if(e instanceof InterruptedException) {
                //响应中断
                e.printStackTrace();
            } else {
                e.printStackTrace();
            }
        } finally {
            try {
                doCleanUp(ex);
            } finally {
                //通知这个token的其他线程
                terminationToken.notifyThreadTermination(this);
            }
        }
    }

    /**
     * 终止线程的操作 （异步的）
     */
    @Override
    public void terminate() {
        terminationToken.setToShutDown(true);
        try {
            doTerminate();
        } finally {
            //如果没有正在执行的任务，试图直接终止线程
            //针对那些正在阻塞等待io或者正在wait状态的线程，调用iterrupt中断他们
            if(terminationToken.reservations.get() <= 0) {
                super.interrupt();
            }
        }
    }

    /**
     * 终止线程 等线程停止了才返回
     *
     * @param waitUtilThreadTerminated
     */
    public void terminate(boolean waitUtilThreadTerminated) {
        terminate();
        if(waitUtilThreadTerminated) {
            try {
                this.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println(this.getName() + "结束");
        }
    }

    /**
     * 线程被中断后的处理
     */
    @Override
    public void interrupt() {
        terminate();
    }

    /**
     * 子类可以实现线程停止后的一些清理任务
     *
     * @param ex
     */
    protected void doCleanUp(Exception ex) {
    }

    /**
     * 留给子类实现线程处理逻辑
     */
    protected abstract void doRun() throws InterruptedException;

    protected void doTerminate() {
    }

}
